import axios, { type AxiosResponse } from "axios";
import { ElMessage } from "element-plus";
import { type allMethodType, type postOrPutType } from "@/constants";
import type { IResult } from "@/types/common";
import { UPLOAD_URL } from "./config";
import type { IUploadQiNiuParams } from "@/types/upload";

/**
 * GET公共请求
 * @param {*} url 请求地址
 * @param {*} params 请求参数
 */
function getAxios<T, D = undefined>(url: string, params?: D) {
  return new Promise<IResult<T>>((resolve, reject) => {
    axios({
      method: "GET",
      url,
      params: params || {}
    })
      .then(res => {
        handleThen<T>(res, resolve, reject);
      })
      .catch(error => {
        console.log(error);
        reject(error);
      });
  });
}

/**
 * POST PUT 请求的公共方法
 * @param {*} url 请求地址
 * @param {*} data 请求参数
 * @param {*} method 请求类型
 */
function commonAxios<T, D>(url: string, data: D, method: postOrPutType) {
  return new Promise<IResult<T>>((resolve, reject) => {
    axios({
      method,
      url,
      data,
      transformRequest: [
        function (data) {
          let ret = "";
          for (const it in data) {
            ret += encodeURIComponent(it) + "=" + encodeURIComponent(data[it]) + "&";
          }
          return ret;
        }
      ]
    })
      .then(res => {
        handleThen<T>(res, resolve, reject);
      })
      .catch(error => {
        console.log(error);
        reject(error);
      });
  });
}

/**
 * 发起通用JSON格式的HTTP请求（POST/PUT方法）
 *
 * @template T 定义响应数据泛型类型
 * @template D 定义请求体数据泛型类型
 * @param {string} url 请求的目标URL地址
 * @param {D} data 要发送的请求体数据
 * @param {postOrPutType} method HTTP方法（限定为post或put类型）
 * @returns {Promise<T>} 返回包含响应数据的Promise对象
 */
function commonAxiosJson<T, D>(url: string, data: D, method: postOrPutType) {
  return new Promise<IResult<T>>((resolve, reject) => {
    axios({
      method,
      url,
      data
    })
      .then(res => {
        handleThen<T>(res, resolve, reject);
      })
      .catch(error => {
        reject(error);
      });
  });
}

/**
 * DELETE公共请求
 *
 * @param {string} url - 请求地址
 * @param {Object} params - 请求参数，是一个对象
 * @returns {Promise} - 返回一个Promise对象，用于处理异步请求的结果
 */
function deleteAxios<T, D>(url: string, params: D) {
  return new Promise<IResult<T>>((resolve, reject) => {
    axios({
      method: "DELETE",
      url,
      params
    })
      .then(res => {
        handleThen<T>(res, resolve, reject);
      })
      .catch(error => {
        reject(error);
      });
  });
}

/* 导出excel 请求 */
function exportExcelAxios<D>(url: string, type: allMethodType, params: D) {
  return new Promise<Blob>((resolve, reject) => {
    axios({
      method: type,
      url: url,
      params: params,
      /* 这里返回类型设置是关键 */
      responseType: "blob",
      transformRequest: [
        function (data) {
          let ret = "";
          for (const it in data) {
            ret += encodeURIComponent(it) + "=" + encodeURIComponent(data[it]) + "&";
          }
          return ret;
        }
      ]
    })
      .then(res => {
        if (res.data.type === "application/json") {
          // 尝试用 FileReader 读取 Blob 数据
          const reader = new FileReader();
          reader.onload = () => {
            try {
              const result = reader.result;
              if (typeof result === "string") {
                const jsonError = JSON.parse(result);
                ElMessage.error(jsonError.msg || "未知错误");
                reject(jsonError);
              } else {
                ElMessage.error("导出失败，响应数据异常");
                reject(res);
              }
            } catch {
              ElMessage.error("解析错误信息失败");
              reject({ msg: "解析错误信息失败" });
            }
          };
          reader.onerror = () => {
            ElMessage.error("文件读取失败");
            reject({ msg: "文件读取失败" });
          };
          reader.readAsText(res.data); // 把 Blob 转成字符串
        } else {
          // 正常文件下载处理
          handleThenExport<Blob>(res, resolve, reject);
        }
      })
      .catch(error => {
        reject(error);
      });
  });
}

/**
 * 图片上传请求
 * @param {*} params 请求参数
 * @param {*} url 请求地址
 */
function uploadImg<T>(params: IUploadQiNiuParams, url = UPLOAD_URL) {
  return new Promise<T>((resolve, reject) => {
    axios({
      method: "POST",
      url: url,
      data: params,
      headers: {
        "Content-Type": "multipart/form-data"
      }
    })
      .then(res => {
        handleThenQiNiu<T>(res, resolve, reject);
      })
      .catch(error => {
        reject(error);
      });
  });
}
/* 七牛云响应的后续处理 */
function handleThenQiNiu<T>(res: AxiosResponse<T>, resolve: (value: T) => void, reject: (value: AxiosResponse) => void) {
  if (res.status !== 200) {
    reject(res);
  } else {
    resolve(res.data);
  }
}

/* 导出响应的后续处理 */
function handleThenExport<T>(res: AxiosResponse<T>, resolve: (value: T) => void, reject: (value: AxiosResponse) => void) {
  if (res.status !== 200) {
    reject(res);
  } else {
    resolve(res.data);
  }
}

/**
 * 处理HTTP响应结果
 *
 * 此函数旨在对Axios响应进行统一处理，根据响应状态决定是解析结果还是抛出错误
 * 它基于HTTP状态码和自定义的数据状态来决定如何处理响应
 *
 * @param res Axios响应对象，包含HTTP状态码和响应数据
 * @param resolve 成功时调用的回调函数，用于传递成功的结果
 * @param reject 失败时调用的回调函数，用于传递失败的原因
 */
function handleThen<T>(res: AxiosResponse<IResult<T>>, resolve: (value: IResult<T>) => void, reject: (value: AxiosResponse) => void) {
  if (res.status !== 200) {
    reject(res);
  } else {
    if (res.data.status === 0) {
      ElMessage.error(res.data.msg);
      reject(res);
    } else {
      resolve(res.data);
    }
  }
}

export { getAxios, commonAxios, commonAxiosJson, deleteAxios, uploadImg, exportExcelAxios };
